package com.supermarket.api.common.logging;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

@Component
@Aspect
@Slf4j
public class LoggingAspect {

    private String getMappingUrl(Class clazz) {
        String url = getClassRequestMappingUrl(clazz);
        if (url == null) {
            url = getClassPostMappingUrl(clazz);
        }
        if (url == null) {
            url = getClassGetMappingUrl(clazz);
        }
        return url;
    }

    private String getClassRequestMappingUrl(Class clazz) {
        RequestMapping mapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
        String url = null;
        if (mapping != null) {
            String[] tem = mapping.value();
            tem = tem == null ? mapping.path() : tem;
            if (tem != null && tem.length > 0) {
                url = tem[0];
            }
        }
        return url;
    }

    private String getClassPostMappingUrl(Class clazz) {
        PostMapping mapping = (PostMapping) clazz.getAnnotation(PostMapping.class);
        String url = null;
        if (mapping != null) {
            String[] tem = mapping.value();
            tem = tem == null ? mapping.path() : tem;
            if (tem != null && tem.length > 0) {
                url = tem[0];
            }
        }
        return url;
    }

    private String getClassGetMappingUrl(Class clazz) {
        GetMapping mapping = (GetMapping) clazz.getAnnotation(GetMapping.class);
        String url = null;
        if (mapping != null) {
            String[] tem = mapping.value();
            tem = tem == null ? mapping.path() : tem;
            if (tem != null && tem.length > 0) {
                url = tem[0];
            }
        }
        return url;
    }

    private String getMethodRequestMappingUrl(Method method) {
        RequestMapping mapping = method.getAnnotation(RequestMapping.class);
        String url = null;
        if (mapping != null) {
            String[] tem = mapping.value();
            tem = tem == null ? mapping.path() : tem;
            if (tem != null && tem.length > 0) {
                url = tem[0];
            }
        }
        return url;
    }

    private String getMethodPostMappingUrl(Method method) {
        PostMapping mapping = method.getAnnotation(PostMapping.class);
        String url = null;
        if (mapping != null) {
            String[] tem = mapping.value();
            tem = tem == null ? mapping.path() : tem;
            if (tem != null && tem.length > 0) {
                url = tem[0];
            }
        }
        return url;
    }

    private String getMethodGetMappingUrl(Method method) {
        GetMapping mapping = method.getAnnotation(GetMapping.class);
        String url = null;
        if (mapping != null) {
            String[] tem = mapping.value();
            tem = tem == null ? mapping.path() : tem;
            if (tem != null && tem.length > 0) {
                url = tem[0];
            }
        }
        return url;
    }

    private String getMethodMappingUrl(Method method) {
        String url = getMethodRequestMappingUrl(method);
        if (url == null) {
            url = getMethodPostMappingUrl(method);
        }
        if (url == null) {
            url = getMethodGetMappingUrl(method);
        }
        return url;
    }

    /**
     * 打印接口时间
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("within(com.supermarket.api.web..*)")
    public Object cost(ProceedingJoinPoint point) throws Throwable {
        Object[] args = point.getArgs();

        long start = System.currentTimeMillis();
        Object result = point.proceed();
        long end = System.currentTimeMillis();

        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        NoLog logs = method.getAnnotation(NoLog.class);
        if(logs != null){
            return result;
        }

        Class<?> targ = point.getTarget().getClass();
        String prefix = getMappingUrl(targ);
        if (prefix == null) {
            prefix = "";
        }
        prefix += "/";

        String subfix = getMethodMappingUrl(method);
        if (subfix != null) {
            prefix += subfix;
        }

        prefix = prefix.replaceAll("//", "/");
        log.info("【接口执行时间】接口：{},执行时间:{}毫秒", prefix, (end - start));
        param(args, prefix);

        return result;
    }

    /**
     * 打印接口参数
     *
     * @return
     * @throws Throwable
     */
    public void param(Object[] args, String url) {
        if (args != null) {
            for (Object obj : args) {
                if (obj == null) {
                    continue;
                }
                if (obj instanceof HttpServletRequest) {
                    continue;
                }
                if (obj instanceof HttpServletResponse) {
                    continue;
                }
                log.info("【接口参数 】 {} : {}", url, JSON.toJSONString(obj));
            }
        }
    }
}
